#ifndef LOG_UTILS_H_
#define LOG_UTILS_H_

#include <algorithm>
#include <cassert>
#include <cstddef>
#include <cstdio>
#include <cstring>

#include "netlib/base/copyable.h"

namespace netlib::detail {

const int kSmallBuffer = 4000;
const int kLargeBuffer = 4000 * 1000;

template <int SIZE = 4000> class Buffer : Copyable {
public:
	void Append(const char* data, int size) { Append(data, static_cast<size_t>(size)); }
	void Append(const char* data, size_t size);
	template <typename T> void AppendInteger(T val);
	void AppendDouble(double val);

	const char* Data() const { return data_; }
	size_t Size() const { return cur_ - data_; }
	size_t WritableSize() const { return End() - cur_; }
	void Reset() { cur_ = data_; }

private:
	size_t GetAvailableLen() const { return End() - cur_; }
	const char* End() const { return data_ + SIZE; }

	char data_[SIZE];
	char* cur_{data_};

	const static int kNumericSize = 32;
};

template <int SIZE> const int Buffer<SIZE>::kNumericSize;

template <int SIZE> void Buffer<SIZE>::Append(const char* data, size_t size) {
	assert(size <= GetAvailableLen());
	if (size <= GetAvailableLen()) {
		memcpy(cur_, data, size);
		cur_ += size;
	}
}

template <int SIZE> template <typename T> void Buffer<SIZE>::AppendInteger(T val) {
	assert(GetAvailableLen() >= kNumericSize);
	val = val >= 0 ? val : -val;
	char* cur_ptr = cur_;
	do {
		int i = static_cast<int>(val % 10);
		*cur_ptr++ = static_cast<char>(i + '0');
		val /= 10;
	} while (val != 0);
	if (val < 0) {
		*cur_ptr++ = '-';
	}
	*cur_ptr = '\0';
	std::reverse(cur_, cur_ptr);
	cur_ = cur_ptr;
}

template <int SIZE> void Buffer<SIZE>::AppendDouble(double val) {
	assert(GetAvailableLen() >= kNumericSize);
	int len = snprintf(cur_, kNumericSize, "%.12g", val);

	cur_ += len;
}

} // namespace netlib::detail

#endif // LOG_UTILS_H_